/***************************************************************************
 *   Copyright (C) 2008 by Łukasz Spintzyk   *
 *   lukasz.spintzyk@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "timer.h"


//!pointer on function which returns current x position of signal. It gives possibility of changing time generator
uint8_t (*getTime)();

/*! Function initializes timer1 necesarry for time base generators. It works in ctc mode, and generates interrupt on OCR1A match.
 */
void initTimer1(){
    
    TCCR1A=0x00;
    TCCR1B=0x08;//SET CTC mode
    OCR1A=15625;//1second when TCNT1=OCR1A then interrupt is generated
    TCNT1=0;
    setPrescaller1(0x05);
    TIMSK|=1<<OCIE1A;
    TCNT1=0;
}

/*! Function sets clock prescaller.
 * \param x value from 0-5, 0-clock stop, 1 - /1 ; 2 - /8 ; 3 - /64 ; 4 - /256 ; 5 - /1024
 */
void setPrescaller1(uint8_t x){
    x&=0x07;
    TCCR1B&=0xF8;
    TCCR1B|=x;
}
/*! Halts timer 1 
 */
void stopTimer1(){
    setPrescaller1(0);
}

/*! In this interrupt data from adc_ext (ch1) is collected
 */
ISR(TIMER1_COMPA_vect){
    
    time++;
    int16_t variable;
    memcpy_P(&variable, &voltValue[curVoltOpt], sizeof(int16_t));
    variable*=(int8_t)(getExtADCValue()-127);
    variable/=UDIV_H;
    variable+=ch1Pos;
    screen_memorych1[getTime()]=variable;
    TCNT1=0;
    
}

/*! Gives us saw shaped time base. Variable adjustFreq adds extra time to time base period(which won't be displayed) for callibration. 
 * \return current x position on display
 */
uint8_t getTimeFromTimer(){

    if (time >= (uint8_t)(DDATA_AREA_SIZE_W + adjustFreq + 1)) time=0;
/* adjustFreq does something like this:
    "Time base period"
    
        _________   - adjust Freq
       /'
      / '
     /  '
    /   '
    DDATA_AREA_SIZE_W
*/
    return time;
}


/*! Gives us time base in shape of signal on channel 2.
 * adjustFreq-128 moves signal characteristic on to left or right,
 *  DDATA_AREA_SIZE/2 is half of screen, minus values means moving signal to left, plus values to right.
 * \return current x position on display.
 */
uint8_t getTimeFromCH2(){
    ADC_conversion&=(uint8_t)~(1<<ADC_AVR);//value is used off
    return adc_avr-127 + DDATA_AREA_SIZE_W/2 +adjustFreq;
}


/*! The same function as getTimeFromTimer(), but with trigger level,
 * adjustFreq is used to indicate the trigger level.Values od adjustFreq from 0-127 rising edge, 128 falling edge.
 * This function works only with external adc(ch1).
 * \return current x position on display
 */
uint8_t getTimeFromTimerWithTriger(){
    static int8_t last_sample=TRIG_LEVEL;

    if( time >=DDATA_AREA_SIZE_W ){
        if ( (adjustFreq<128) && (adc_ext > 2*adjustFreq) && (adc_ext > last_sample) ) time =0;    //rising edge
 
        if ( (adjustFreq>127) && (adc_ext<(adjustFreq-128)*2) && (adc_ext<last_sample) )time =0;

        else time=DDATA_AREA_SIZE_W;

    }
    last_sample=adc_ext;
    return time;
}


/*! Set time which timer1 will count in CTC mode 
 * \param t time to count in ms
 */
void setTime_ms(uint16_t t){
    // (prescaler/F_CPU * 65536*1000)       - 65536 =2^16,  1000-> in ms
    uint16_t val;
    if (t<=(uint16_t)((1.01/F_CPU) * 65536* 1000)){
        setPrescaller1(1);
        val=t/((1*1000.0)/F_CPU);
    }
    else if (t <= (uint16_t)((8.0/F_CPU) * 65536* 1000)){
        setPrescaller1(2);
        val=t/((8*1000.0)/F_CPU);
    }
    else if (t <= (uint16_t)((64.0/F_CPU) * 65536* 1000)){
        setPrescaller1(3);
        val=t/((64*1000.0)/F_CPU);
    }
    else if (t <= (uint16_t)((256.0/F_CPU) * 65536* 1000)){
        setPrescaller1(4);
        val=t/((256*1000.0)/F_CPU);
    }
    else if (t <= (uint16_t)((1024.0/F_CPU) * 65536* 1000)){
        setPrescaller1(5);
        val=t/((1024*1000.0)/F_CPU);
    }
    else val=0xFFFF;
    
    OCR1A=val;
    TCNT1=0;
}


/*! Set time which timer1 will count in CTC mode 
 * \param t time to count in us
 */
void setTime_us(uint16_t t){
    // (prescaler/F_CPU * 65536*1000)       - 65536 =2^16,  1000000-> in us
    uint16_t val;
    if (t<=(uint16_t)((1.0/F_CPU) * 65536* 1000000)){
        setPrescaller1(1);
        val=t/((1*1000000.0)/F_CPU);
    }
    else if (t <= (uint16_t)((8/F_CPU) * 65536* 1000000)){
        setPrescaller1(2);
        val=t/((8*1000000.0)/F_CPU);
    }
    else if (t <= (uint16_t)((64/F_CPU) * 65536* 1000000)){
        setPrescaller1(3);
        val=t/((64*1000000.0)/F_CPU);
    }
    else if (t <= (uint16_t)((256/F_CPU) * 65536* 1000000)){
        setPrescaller1(4);
        val=t/((256*1000000.0)/F_CPU);
    }
    else if (t <= (uint16_t)((1024/F_CPU) * 65536* 1000000)){
        setPrescaller1(5);
        val=t/((1024*1000000.0)/F_CPU);
    }
    else val=0xFFFF;
    
    OCR1A=val;
    TCNT1=0;
}
